home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / lib / obsolete / widbuild.pro < prev    next >
Text File  |  1997-07-08  |  17KB  |  504 lines

  1. ;
  2. ; $Id: widbuild.pro,v 1.11 1997/01/15 03:11:50 ali Exp $
  3. ;
  4. ;  WidBuild
  5. ;   Widget Editor common routines related to building dialog boxes. Mostly.
  6. ;
  7. ; Copyright (c) 1993-1997, Research Systems, Inc.  All rights reserved.
  8. ;   Unauthorized reproduction prohibited.
  9. ;
  10. ; MODIFICATION HISTORY
  11. ;       Written by:     Joshua Goldstein,       12/93
  12. ;
  13.  
  14.  
  15. ;
  16. ;  MakeBaseObj
  17. ;       Create a base object of the given type.  All use the same structure
  18. ;   but are different object types (MAIN, DEP, BASE)
  19. ;
  20. PRO MakeBaseObj, Parent, Obj, Type
  21.  
  22.     Obj = {                     $
  23.         WE_BASE,                $
  24.         Type:           Type,   $ ; Set Type
  25.         Parent:         Parent, $ ; Pointer to parent
  26.         Id:             NewId(),$ ; Permanent Id
  27.         TB_Showing:     1,      $ ; Is Tool Bar Showing?
  28.         Dialog:         0L,     $
  29.         AttrDlg:        0L,     $
  30.         Next:           0L,     $
  31.         Name:           '',     $ ; Title or object name
  32.         Children:       0L,     $ ; linked list of children
  33.         LastChild:      0L,     $ ; Last child (makes adding children easier)
  34.         FrameSize:      0,      $
  35.         EventFunc:      '',     $ ; UNUSED.
  36.         EventProc:      '',     $
  37.         GetFunc:        '',     $ ; func_get_value
  38.         SetProc:        '',     $ ; pro_set_value
  39.         KillProc:       '',     $ ; kill_notify
  40.         XSize:          0,      $
  41.         YSize:          0,      $
  42.         XOffset:        0,      $
  43.         YOffset:        0,      $
  44.         UValue:         '',     $
  45.         Space:          0,      $
  46.         XPad:           0,      $
  47.         YPad:           0,      $
  48.         BaseType:       1,      $ ; Enum { BBS, Row, Col } (Row is dflt)
  49.         NRowCol:        1,      $ ; Number of Rows/Columns
  50.         BaseMapped:     1,      $ ; Is Base Visible?
  51.         TLBEvents:      0,      $ ; Base accepts TLB size events?
  52.         XScrollSize:    0,      $
  53.         YScrollSize:    0       $
  54.     }
  55. END
  56.  
  57.  
  58. ;
  59. ;  MakeAddMenu
  60. ;   Create a series of pulldown menu items based on the class
  61. ;   definition list
  62. ;
  63. FUNCTION MakeAddMenu
  64.  
  65.   COMMON WidEd_Comm
  66.  
  67.     Dummy       = { CW_PDMENU_S, flags:0, name:'' }
  68.     Menu        = REPLICATE(Dummy, N_ELEMENTS(AddList))
  69.     Menu.name   = AddList.Menu
  70.     RETURN, Menu
  71. END
  72.  
  73.  
  74. ;
  75. ;  ToolBar_Event
  76. ;       Repackage a button press to look like a menu press
  77. ;
  78. PRO ToolBar_Event, Event
  79.  
  80.   COMMON WidEd_Comm
  81.  
  82.     ;   We will need the pointer for the Object associated with this
  83.     ;   dialog box (the parent for the children we are about to create)
  84.  
  85.     ;   Can't use /NO_COPY because AddChild assumed TopDlg's UVALUE
  86.     ;   will always be valid and Event.Top may be TopDlg
  87.  
  88.     WIDGET_CONTROL, Event.top, GET_UVALUE=Binfo
  89.  
  90.     WIDGET_CONTROL, Event.Id, GET_UVALUE=Build
  91.  
  92.     ;   Allocate object and create a dialog box as well
  93.     CALL_PROCEDURE, Build + '_Build', Ptr, Binfo.ObjPtr
  94.  
  95.     ;   Add child to our child list.  Note that Base object
  96.     ;   do not get added to the active dialog box list
  97.     AddChild, Binfo.ObjPtr, Ptr, NO_CANCEL=(Build EQ 'Base')
  98.  
  99.     ;   Restore dialog box information
  100.     WIDGET_CONTROL, Event.top, SET_UVALUE=Binfo, /NO_COPY
  101. END
  102.  
  103.  
  104. ;
  105. ;  BuildToolBar
  106. ;   Create a series of bitmapped buttons
  107. ;
  108. PRO BuildToolBar, Base, ToolBase
  109.  
  110.   COMMON WidEd_Comm
  111.  
  112.     I=0
  113.     N=N_ELEMENTS(AddList)
  114.     WHILE I LT N DO BEGIN
  115.         Icon    = CALL_FUNCTION(Addlist[I].Class + "_Icon")
  116.         IF N_ELEMENTS(Icon) NE 1 THEN BEGIN
  117.             ToolBase    = WIDGET_BASE(Base, /ROW, /FRAME, $
  118.                                 SPACE=1, EVENT_PRO='ToolBar_Event')
  119.             FOR I=0,N-1 DO BEGIN
  120.                 Icon    = CALL_FUNCTION(Addlist[I].Class + "_Icon")
  121.                 IF N_ELEMENTS(Icon) NE 1 THEN BEGIN
  122.                      Button     = WIDGET_BUTTON(ToolBase, VALUE=Icon, $
  123.                                                 UVALUE=AddList[I].Class)
  124.                 ENDIF
  125.             ENDFOR
  126.         ENDIF
  127.  
  128.     ENDWHILE
  129.  
  130. END
  131.  
  132.  
  133.  
  134. ;
  135. ;  Field
  136. ;       Common entry point for creation of a dialog box information entry
  137. ;   object (CW_FIELD) for user entry of a value.  Simpler to use
  138. ;   layer because we can change options in a single location (here)
  139. ;   for (near) global effect.
  140. ;
  141. ;   Returns Widget Id.
  142. ;
  143. FUNCTION Field, Base, Title, Value, Uvalue, $
  144.     SIZE=Size, INT=Int, STRING=String, LONG=Long, FLOAT=Float
  145.  
  146.   COMMON WidEd_Comm
  147.  
  148.     RETURN, CW_FIELD(Base, TITLE=Title, VALUE=Value, UVALUE=Uvalue, $
  149.                 XSIZE=Size, /ALL_EVENTS, TEXT_FRAME=OnAPC, $
  150.                 INT=Int, STRING=String, LONG=Long, FLOAT=Float)
  151. END
  152.  
  153.  
  154. ;
  155. ;  BuildBaseType
  156. ;   All base objects have within them a sub base used to set base
  157. ;   type information (row v. column, child spacing, etc.).
  158. ;
  159. ;   Create that information.  Builder provides object information,
  160. ;
  161. ;   The fields created are used to fill in Focus information starting
  162. ;   FOff.  Btns are saved for later showing user object state.
  163. ;   RowColId is needed by the parent dialog for enabling/disabling
  164. ;   Row-Column information as user changed base type selection.
  165. ;
  166. PRO BuildBaseType, Base, Obj, Foci, FOff, RowColId, Btns, ROW=Row
  167.  
  168.     Btns    = LONARR(3)
  169.  
  170.     ;   Events get sent to object's event routine (should be called XXX_Event
  171.     Base1   = WIDGET_BASE(Base, /COLUMN, /FRAME, EVENT_PRO=Obj.Type+'_Event')
  172.  
  173.     ;   Support different widget layouts
  174.  
  175.     IF KEYWORD_SET(Row) THEN BEGIN
  176.         BBase   = WIDGET_BASE(Base1, /ROW)
  177.         LabVal  = "Base Type:"
  178.     ENDIF ELSE BEGIN
  179.         BBase   = Base1
  180.         LabVal  = "Base Type"
  181.     ENDELSE
  182.  
  183.     ;   Create subbase contents
  184.  
  185.     Label   = WIDGET_LABEL(BBase, VALUE=LabVal)
  186.     Base2   = WIDGET_BASE(BBase, /ROW, /EXCLUSIVE)
  187.     Btns[1] = WIDGET_BUTTON(Base2, VALUE='Row', UVALUE='Row', /NO_RELEASE)
  188.     Btns[2] = WIDGET_BUTTON(Base2, VALUE='Column', UVALUE='Column', /NO_REL)
  189.     Btns[0] = WIDGET_BUTTON(Base2, VALUE='Bulletin Board',  $
  190.                     UVALUE='Bbs', /NO_RELEASE)
  191.  
  192.     RowColId        = WIDGET_BASE(Base1, /COLUMN)
  193.     Foci[FOff]      = Field(RowColId,"Number of Rows/Columns", $
  194.                         Obj.NRowCol, "NROW", /INT, SIZE=5)
  195.     RCBase          = WIDGET_BASE(RowColId, /ROW)
  196.     Foci[FOff+1]    = Field(RcBase, 'Child Spacing:', $
  197.                         Obj.Space, "SPACE", /INT, SIZE=8)
  198.     Foci[FOff+2]    = Field(RcBase, 'X Padding:', $
  199.                         Obj.XPad, "XPAD", /INT, SIZE=8)
  200.     Foci[FOff+3]    = Field(RcBase, 'Y Padding:', $
  201.                         Obj.YPad, "YPAD", /INT, SIZE=8)
  202. END
  203.  
  204.  
  205. ;
  206. ;  BuildXY
  207. ;   Every one of the dialog boxes have some fields which control
  208. ;   object size, position and/or scroll size.  This routine creates
  209. ;   the fields for controlling that information.
  210. ;
  211. ;   If only 1 keyword is specified, put the X & Y fields in the same row,
  212. ;   otherwise, put all the X information in a top row and all the Y
  213. ;   information in a lower row.
  214. ;
  215. ;   The implementation of this routine is obscure. Sorry.
  216. ;   However, the usage is pretty straight forward. (c.f. XXX_Build routines)
  217. ;
  218. PRO BuildXY, Base, Obj, Foci, FOff, $
  219.     SCROLL=DoScroll, SIZE=DoSize, OFFSET=DoOffset, ALL=All
  220.  
  221.     ;   Make all of the flags have a value of 0 or 1
  222.  
  223.     DoSize      = KEYWORD_SET(DoSize)
  224.     DoOffset    = KEYWORD_SET(DoOffset)
  225.     DoScroll    = KEYWORD_SET(DoScroll)
  226.  
  227.     IF KEYWORD_SET(All) THEN BEGIN
  228.         DoSize      = 1
  229.         DoOffset    = 1
  230.         DoScroll    = 1
  231.     ENDIF
  232.  
  233.     ;   Y entries will be after X entries
  234.     YOff = DoSize + DoOffset + DoScroll
  235.  
  236.     ;   Single request?  Make a single row
  237.  
  238.     IF YOff EQ 1 THEN BEGIN
  239.         Base1   = WIDGET_BASE(Base, /ROW, EVENT_PRO=Obj.Type+'_Event')
  240.         Base2   = Base1
  241.         Base3   = Base1
  242.  
  243.     ;   Multiple types? Make an X and a Y row
  244.     ENDIF ELSE BEGIN
  245.         Base1   = WIDGET_BASE(Base, /COLUMN, EVENT_PRO=Obj.Type+'_Event')
  246.         Base2   = WIDGET_BASE(Base1, /ROW)
  247.         Base3   = WIDGET_BASE(Base1, /ROW)
  248.     ENDELSE
  249.  
  250.     ;   Create Size entries
  251.     IF DoSize THEN BEGIN
  252.         Foci[Foff]      = Field(Base2, "X Size:", Obj.XSize, "XSIZE", $
  253.                                 /INT, SIZE=8)
  254.         Foci[Foff+YOff] = Field(Base3, "Y Size:", Obj.YSize, "YSIZE", $
  255.                                 /INT, SIZE=8)
  256.     ENDIF
  257.  
  258.     ;   Create Offset Entries
  259.     IF DoOffset THEN BEGIN
  260.         Off = FOff + DoSize
  261.         Foci[Off]       = Field(Base2, "X Offset:", Obj.XOffset, "XOFFSET", $
  262.                                 /INT, SIZE=8)
  263.         Foci[Off+YOff]  = Field(Base3, "Y Offset:", Obj.YOffset, "YOFFSET", $
  264.                                     /INT, SIZE=8)
  265.     ENDIF
  266.  
  267.     ;   Create Scrollsize Entries
  268.     IF DoScroll THEN BEGIN
  269.         Off = FOff + DoSize + DoOffset
  270.         Foci[Off]       = Field(Base2, "X Scroll Size:", $
  271.                                     Obj.XScrollSize, "XSCROLL", /INT, SIZE=8)
  272.         Foci[Off+YOff]  = Field(Base3, "Y Scroll Size:", $
  273.                                     Obj.YScrollSize, "YSCROLL", /INT, SIZE=8)
  274.     ENDIF
  275. END
  276.  
  277.  
  278. ;
  279. ;  BuildOkCancel
  280. ;
  281. ;   Create Done and Cancel buttons.  Common to the dialog of
  282. ;   many object classes.
  283. ;
  284. PRO BuildOkCancel, Base, Obj
  285.  
  286.     Dummy       = WIDGET_LABEL(Base, VALUE=' ')
  287.     Base1       = WIDGET_BASE(Base, /ROW, EVENT_PRO=Obj.Type+'_Event')
  288.     DoneTxt     = '          Done         '
  289.     CancelTxt   = '         Cancel        '
  290.     Dummy       = WIDGET_BUTTON(Base1, VALUE=DoneTxt, UVALUE='DONE' )
  291.     Dummy       = WIDGET_BUTTON(Base1, VALUE=CancelTxt, UVALUE='CANCEL' )
  292. END
  293.  
  294.  
  295. ;
  296. ;  BuildOther
  297. ;
  298. ;   Many dialogs have a Name, Frame and UVALUE entry.  Common support
  299. ;   for creating those items.
  300. ;
  301. PRO BuildOther, Base, Obj, Foci, FOff, FRAME=Frame
  302.  
  303.     Base1           = WIDGET_BASE(Base, FRAME=KEYWORD_SET(Frame), /COLUMN)
  304.     Lab             = WIDGET_LABEL(Base1, VALUE="Other Controls")
  305.     Foci[Foff]      = Field(Base1, "Name:", Obj.Name, 'NAME', SIZE=50, /STRING)
  306.     Base2           = WIDGET_BASE(Base1, /ROW)
  307.     Foci[Foff+1]    = Field(Base2, "Frame Size:", Obj.FrameSize, $
  308.                             "FRAME", /INT, SIZE=8)
  309.     Foci[Foff+2]    = Field(Base2, "User Value:", Obj.UValue, "UVALUE", $
  310.                             SIZE=20, /STRING)
  311. END
  312.  
  313. ;
  314. ;  BuildEdit
  315. ;   Dialogs for objects which have a STRARR for a value (LIST, BGROUP, etc.)
  316. ;   need a Edit Control for entering said text.  Common code for
  317. ;   building that portion of the dialog
  318. ;
  319. ;   Commented portions should be uncommented to add support for using
  320. ;   IDL code to generate VALUE (v. Literal strings).
  321. ;   This cannot work until EXECUTE won't stop the editor if the user
  322. ;   has a typo
  323. ;
  324. PRO BuildEdit, Base, Obj, Edit, SINGLE=Single
  325.  
  326.     Base1       = WIDGET_BASE(Base, /FRAME, /COLUMN)
  327.     Label       = WIDGET_LABEL(Base1, VALUE=Obj.Type + " Widget Value")
  328.     Base2       = WIDGET_BASE(Base1, /ROW)
  329. ;   Base3       = WIDGET_BASE(Base2, /COLUMN, /EXCLUSIVE)
  330. ;   Button1     = WIDGET_BUTTON(Base3, VALUE="Use Literal Text", $
  331. ;                           UVALUE="LITERAL")
  332. ;   WIDGET_CONTROL, Button1, /SET_BUTTON
  333. ;   Button2     = WIDGET_BUTTON(Base3, VALUE="Use IDL Code", $
  334. ;                           UVALUE="CODEBASED");
  335. ;   WIDGET_CONTROL, Button2, SENSITIVE=0
  336.  
  337.     Base3       = WIDGET_BASE(Base2, /COLUMN)
  338.     WIDGET_CONTROL, Obj.Value1, GET_UVALUE=StrValue
  339.     IF KEYWORD_SET(Single) THEN YSize=1 ELSE YSize=5
  340.     MainText    = CW_FIELD(Base3, XSIZE=50, YSIZE=YSize, /ALL, TITLE=" ", $
  341.                         VALUE=StrValue, UVALUE='MAINTEXT')
  342. ;   Edit        = CW_FIELD(Base3, XSIZE=44, /ALL, TITLE="VALUE=", $
  343. ;                       VALUE=Obj.Value2, UVALUE='VALUETEXT')
  344. ;   WIDGET_CONTROL, Edit, SENSITIVE=Obj.ValueType
  345.     Edit        = 0L
  346. END
  347.  
  348.  
  349. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  350. ;
  351. ;   General Event Routines
  352. ;
  353. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  354.  
  355. ;
  356. ;  DoXFont
  357. ;   Run the XFont utility to allow the user to choose a font.
  358. ;   Set the 'Font:' field to correspond to the user's choice.
  359. ;   Only runs on a system running X.
  360. ;
  361. PRO DoXFont, Obj, Id
  362.     WIDGET_CONTROL, /HourGlass
  363.     NewFontName = XFont()
  364.     IF NewFontName NE '' THEN BEGIN
  365.         WIDGET_CONTROL, Id, SET_VALUE=NewFontName
  366.         Obj.Font    = NewFontName
  367.     ENDIF
  368. END
  369.  
  370. ;
  371. ;  MISC_Kill
  372. ;   Called whenever an active dialog box is destroyed (except for
  373. ;   base objects [DEP and BASE]).  IF the dialog still has
  374. ;   information attached to it AND the object has not been destroyed
  375. ;   THEN clear the dialog widget id contained in the object -- indicating
  376. ;   that it no longer has an active dialog box associated with it.
  377. ;
  378. PRO MISC_Kill, Dlg
  379.  
  380.   COMMON WidEd_Comm
  381.  
  382.     ;   Get dialog info
  383.     WIDGET_CONTROL, Dlg, GET_UVALUE=Binfo, /NO_COPY
  384.  
  385.     IF KEYWORD_SET(Binfo) THEN BEGIN        ; Dialog info valid?
  386.  
  387.         IF WIDGET_INFO( BInfo.ObjPtr, /VALID) THEN BEGIN    ; ObjPtr valid?
  388.  
  389.             Ptr2Obj, Binfo.ObjPtr, Obj      ; Get Object
  390.  
  391.             ;   We may not have any object associated with the
  392.             ;   dialog -- if we here as a result of the object
  393.             ;   being destroyed programmatically.  In that case,
  394.             ;   just don't do anything
  395.  
  396.             IF N_ELEMENTS(Obj) NE 0 THEN BEGIN  ; Object Valid?
  397.                 Obj.Dialog = 0L                 ; Clear Dialog Id
  398.                 Obj2Ptr, Obj, Binfo.ObjPtr      ; put object back into pointer
  399.             ENDIF
  400.  
  401.             ;   See if we have a copy of this object (allows cancel to work)
  402.             ;   If we do, delete extra copy of the object and update the
  403.             ;   active list
  404.  
  405.             Idx = WHERE(NewDialogs.ObjPtr EQ Binfo.ObjPtr, Count)
  406.             IF Count EQ 1 THEN BEGIN
  407.  
  408.                 Idx     = Idx[0]    ; Where it is in the active list
  409.  
  410.                 ;   Destroy the copy.  BASE objects should never be in
  411.                 ;   NewDialogs. Copy (oldptr) may have a valid pointer to
  412.                 ;   the dialog. This is bad. If there is a copy and it is
  413.                 ;   destroyed, the dialog would be destroyed twice (once
  414.                 ;   by user action, once by this routine. The second
  415.                 ;   deletion would fail and crashes the widget editor)
  416.  
  417.                 IF NewDialogs[Idx].OldPtr NE 0L THEN BEGIN
  418.                     Ptr = NewDialogs[Idx].OldPtr    ; Get Copy Pointer
  419.                     Ptr2Obj, Ptr, Obj               ; Get copy object
  420.  
  421.                     ;  There may exist a point in destroying a dialog
  422.                     ;  where we are in the process of destroying the
  423.                     ;  object associated with this dialog and hence
  424.                     ;  things are half destroyed so we check for that
  425.                     IF N_ELEMENTS(Obj) NE 0 THEN BEGIN
  426.                         Obj.Dialog      = 0         ; Clear dialog box pointer
  427.                         Obj2Ptr, Obj, Ptr           ; Put obj back into pointer
  428.                         Destroy, Ptr            ; Destroy it (but not dialog)
  429.                     ENDIF
  430.                 ENDIF
  431.  
  432.                 ;   Now we have to remove the deleted object from the list
  433.                 ;   of objects with active dialog boxes.
  434.  
  435.                 N   = N_ELEMENTS(NewDialogs)
  436.                 IF Idx EQ N-1 THEN $                    ; Last active object?
  437.                     NewDialogs  = NewDialogs[0:N-2] $
  438.                 ELSE $
  439.                     NewDialogs  = [ NewDialogs[0:Idx-1], NewDialogs[Idx+1,*] ]
  440.             ENDIF
  441.         ENDIF
  442.     ENDIF
  443.  
  444. END
  445.  
  446. ;
  447. ;  MISC_Event
  448. ;   Event processing for simple dialog boxes.  Used by many
  449. ;   of the simple object classes.
  450. ;
  451. PRO MISC_Event, Event, FontIdx
  452.  
  453.   COMMON WidEd_Comm 
  454.  
  455.     WIDGET_CONTROL, Event.Id, GET_UVALUE=Ev                 ; Get Event
  456.     WIDGET_CONTROL, Event.Top, GET_UVALUE=Binfo, /NO_COPY   ; Get Dialog info
  457.     Ptr2Obj, Binfo.ObjPtr, Obj                              ; Get Object
  458.  
  459.     CASE Ev OF
  460.  
  461.     'VALUE':    Obj.Value       = Event.Value               ; Generic Fields
  462.     'FONT':     Obj.Font        = Event.Value
  463.     'NAME':     Obj.Name        = Event.Value
  464.     'FRAME':    Obj.FrameSize   = Event.Value
  465.     'UVALUE':   Obj.Uvalue      = Event.Value
  466.     'XSIZE':    Obj.XSize       = Event.Value
  467.     'YSIZE':    Obj.YSize       = Event.Value
  468.     'XOFFSET':  Obj.XOffset     = Event.Value
  469.     'YOFFSET':  Obj.YOffset     = Event.Value
  470.     'XSCROLL':  Obj.XScrollSize = Event.Value
  471.     'YSCROLL':  Obj.YScrollSize = Event.Value
  472.  
  473.     'XFONT':    DoXFont, Obj, Binfo.Foci[FontIdx]
  474.  
  475.     'DO_BUTTON':    Obj.DrawBtnEv   = 1 - Obj.DrawBtnEv     ; DRAW Widget only
  476.     'DO_MOTION':    Obj.DrawMoEv    = 1 - Obj.DrawMoEv
  477.     'NO_STORE':     Obj.DrawRetain  = 0
  478.     'SVR_STORE':    Obj.DrawRetain  = 1
  479.     'IDL_STORE':    Obj.DrawRetain  = 2
  480.  
  481.     'DONE':     BEGIN
  482.         Accept, Obj, Binfo.ObjPtr
  483.         WIDGET_CONTROL, Event.Top, SET_UVALUE=Binfo, /NO_COPY
  484.         WIDGET_CONTROL, Event.Top, /DESTROY
  485.         RETURN
  486.         END
  487.  
  488.     'CANCEL':   BEGIN
  489.         Cancel, Obj, Binfo.ObjPtr
  490.         RETURN
  491.         END
  492.     ELSE:           MESSAGE, 'Unprocessed event: ' + Ev
  493.     ENDCASE
  494.  
  495.     Dirty   = 1     ; We've changed something since the last save
  496.  
  497.     SetNextFocus, Binfo, Event      ; Set next keyboard focus as necessary
  498.     Obj2Ptr, Obj, Binfo.ObjPtr      ; Put object back into pointer
  499.     WIDGET_CONTROL, Event.Top, SET_UVALUE=Binfo, /NO_COPY
  500. END
  501.  
  502. PRO WidBuild
  503. END
  504.